package com.luxk.db.server;

import java.io.File;
import java.io.IOException;
import java.util.Stack;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.luxk.db.common.ImpactException;
import com.luxk.db.common.Module;
import com.luxk.db.errorcode.ErrorCodeServer;
import com.luxk.util.BeanUtil;

public class ServerInstanceBuilder {

	public Server build(String xmlPath) throws ImpactException {
		DefaultHandler dh = null;
		try {
			SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
			File f = new File(xmlPath);
			dh = new ServerBuilderHandler();
			parser.parse(f, dh);
		} catch (Exception e) {
			throw new ImpactException(
					ErrorCodeServer.ERROR_CREATE_SERVER_INSTANCE, e);
		}
		
		return ((ServerBuilderHandler)dh).getServer();
	}
}

class ServerBuilderHandler extends DefaultHandler {
	
	private Server server = null;
	private Stack<Object> stack = new Stack<Object>();
	
	public void startElement(String uri, String localName, String qName,
			Attributes atts) throws SAXException {
		/*
		System.out.println("startElement qName: " + qName);
		int len = atts.getLength();
		for(int i = 0; i < len; i++)
			System.out.println("  Attr #" + i +
					" key:" + atts.getQName(i) + ", val:" + atts.getValue(i));
		*/
		
		try {
			if("server".equalsIgnoreCase(qName)) {
				buildServer(qName, atts);
			} else if("modules".equalsIgnoreCase(qName)) {
				buildModules(qName, atts);
			} else if("parameters".equalsIgnoreCase(qName)) {
				buildParameters(qName, atts);
			} else if("module".equalsIgnoreCase(qName)) {
				buildModule(qName, atts);
			} else if("parameter".equalsIgnoreCase(qName)) {
				buildParameter(qName, atts);
			} else {
				throw new Exception("Invalid xml defs(" + qName + ")");
			}
		} catch(Exception e) {
			throw new SAXException(e.getMessage(), e);
		}
	}

	public void endElement(String uri, String localName, String qName) {
		if("module".equalsIgnoreCase(qName)) {
			Module m = (Module)this.stack.pop();
			if(this.stack.empty()) {
				this.server.addModule(m);
			} else {
				Module p = (Module)this.stack.peek();
				p.addSubModule(m);
			}
		}
	}
	
	public void characters(char[] chars, int start, int length) {
		// do nothing
	}
	
	public Server getServer() { return this.server; }
	
	private void buildServer(String qName, Attributes atts) throws Exception {
		String className = atts.getValue("className");
		
	    if( className == null || className.equals( "" ) )
	        throw new Exception( qName + " attribute className missed" );
	    
	    this.server = (Server)Class.forName(className).newInstance();
	    
		int len = atts.getLength();
		for(int i = 0; i < len; i++) {
			if("className".equalsIgnoreCase(atts.getQName(i)))
				continue;
			
			BeanUtil.setProperty(this.server, atts.getQName(i),
					atts.getValue(i));
		}
	}
	
	private void buildModules(String qName, Attributes atts) throws Exception {
		
	}
	
	private void buildParameters(String qName, Attributes atts) throws Exception {
		
	}
	
	private void buildModule(String qName, Attributes atts) throws Exception {
		String className = atts.getValue("className");
		
	    if( className == null || className.equals( "" ) )
	        throw new Exception( qName + " attribute className missed" );

	    Module m = (Module)Class.forName(className).newInstance();

	    int len = atts.getLength();
		for(int i = 0; i < len; i++) {
			if("className".equalsIgnoreCase(atts.getQName(i)))
				continue;
			
			BeanUtil.setProperty(m, atts.getQName(i), atts.getValue(i));
		}
		
		this.stack.push(m);
	}
	
	private void buildParameter(String qName, Attributes atts) throws Exception {
		
	}
}